package com.platform.api;

import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.CONNECT_OAUTH2_AUTHORIZE_URL;

import java.io.IOException;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.platform.controller.BaseController;
import com.platform.entity.MpMsgEntity;
import com.platform.entity.UserEntity;
import com.platform.service.MpMsgService;
import com.platform.service.TokenService;
import com.platform.service.UserService;
import com.platform.utils.MapUtils;
import com.platform.utils.R;
import com.platform.utils.RequestUtil;
import com.platform.utils.ResourceUtil;
import com.platform.utils.StringUtils;
import com.platform.wx.mp.config.WxMaConfiguration;
import com.platform.wx.mp.config.WxMpConfiguration;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.URIUtil;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;


@Controller
@RequestMapping("/wxlogin")
public class ApiWxLoginController extends BaseController{
    private Logger logger = Logger.getLogger(getClass());
    
    @Autowired
    private UserService userService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private MpMsgService mpMsgService;
    @Autowired
    private WxMpConfiguration wxMpConfiguration;
    
    @Autowired
    private WxMaConfiguration wxMaConfiguration;
///////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////      公众号  					///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////
    /**
     * j静默登录
     * @return
     */
    @RequestMapping(value = "/mpsilentlogin/{mpId}")
    public String silentLogin(
    		@PathVariable("mpId") Integer mpId,
    		HttpServletRequest request, HttpServletResponse response,ModelMap map) {
	    try {
	    	MpMsgEntity mpMsg = mpMsgService.queryObject(mpId);
	        WxMpService weixinService = wxMpConfiguration.getMpService(mpId);
			response.sendRedirect(String.format(CONNECT_OAUTH2_AUTHORIZE_URL.getUrl(weixinService.getWxMpConfigStorage()),
					mpMsg.getAppId(), 
					URIUtil.encodeURIComponent(ResourceUtil.getConfigByName("home.url") + "/wxlogin/mpsilentlogin/back/" + mpId), 
					WxConsts.OAuth2Scope.SNSAPI_BASE, ""));
			return null;
		} catch (IOException e) {
        	map.put("errorMsg", "系统异常：" + e.getMessage());
			return "wx/wx-login-exception";
		}
    }
    
    @RequestMapping(value = "/mpsilentlogin/back/{mpId}")
    public String silentLoginBackUniApp(@PathVariable("mpId") Integer mpId,
    		HttpServletRequest request, HttpServletResponse response,ModelMap map) {
        String code = request.getParameter("code");
    	MpMsgEntity mpMsg = mpMsgService.queryObject(mpId);
        try {
            if(code == null) {
            	map.put("errorMsg", "code不能为空!");
    			response.sendRedirect(mpMsg.getHomeUrl() + "#/pages/error/wx_error?errorMsg=codeisnull");
    			return null;
            }
			response.sendRedirect(mpMsg.getWxCheckCodeUrl() + "?code=" + code);
			return null;
		} catch (IOException e) {
        	map.put("errorMsg", "系统异常：" + e.getMessage());
			return "系统异常：" + e.getMessage();
		}
    }
    
    @ResponseBody
    @RequestMapping(value = "/checksilentlogincode/{mpId}")
    public R checkSilentLoginCode(@PathVariable("mpId") Integer mpId,
    		HttpServletRequest request, HttpServletResponse response) {
        String code = request.getParameter("code");
        Integer referenceId = null;
        if(request.getParameter("referenceId") != null) {
        	try {
				referenceId = Integer.valueOf(request.getParameter("referenceId"));
			} catch (NumberFormatException e) {
				referenceId = 0;
			}
        }
        UserEntity user = null;
        WxMpService weixinService = wxMpConfiguration.getMpService(mpId);
        if (!StringUtils.isNullOrEmpty(code)) {
            try {
				WxMpOAuth2AccessToken accessToken = weixinService.oauth2getAccessToken(code);
				WxMpUser wxMpUser = weixinService.getUserService().userInfo(accessToken.getOpenId());
				String ip = RequestUtil.getIpAddrByRequest(request);
				user = userService.loginByWx(wxMpUser,mpId,ip,referenceId);
			} catch (WxErrorException e) {
				logger.error(e.getMessage(),e);
				return R.error(e.getMessage());
			}
        }else {
			logger.error("code is null");
			return R.error("code is null");
        }
	    Map<String, Object> tokenMap = tokenService.createToken(user.getId());
	    String token = MapUtils.getString("token",tokenMap);
		return R.ok().put("user", user).put("token", token).put("expireTime", tokenMap.get("expireTime"));
    }
    
    
    
    /**
     * s授权登录
     * @param mpId
     * @param request
     * @param response
     * @param map
     * @return
     */
    @RequestMapping(value = "/gencode/{mpId}")
    public String genCode(
    		@PathVariable("mpId") Integer mpId,
    		HttpServletRequest request, HttpServletResponse response,ModelMap map) {
	    try {
	    	MpMsgEntity mpMsg = mpMsgService.queryObject(mpId);
	        WxMpService weixinService = wxMpConfiguration.getMpService(mpId);
			response.sendRedirect(String.format(CONNECT_OAUTH2_AUTHORIZE_URL.getUrl(weixinService.getWxMpConfigStorage()),
					mpMsg.getAppId(), 
					URIUtil.encodeURIComponent(ResourceUtil.getConfigByName("home.url") + "/wxlogin/back/" + mpId), 
					WxConsts.OAuth2Scope.SNSAPI_USERINFO, ""));
			return null;
		} catch (IOException e) {
        	map.put("errorMsg", "系统异常：" + e.getMessage());
			return "wx/wx-login-exception";
		}
    }

    @RequestMapping(value = "/back/{mpId}")
    public String backUniApp(@PathVariable("mpId") Integer mpId,
    		HttpServletRequest request, HttpServletResponse response,ModelMap map) {
        String code = request.getParameter("code");
        
        logger.info("====================code:" + code);
        
        if(code == null) {
        	map.put("errorMsg", "code不能为空!");
			return "wx/wx-login-exception";
        }
        try {
	    	MpMsgEntity mpMsg = mpMsgService.queryObject(mpId);
			response.sendRedirect(mpMsg.getWxCheckCodeUrl() + "?code=" + code);
			return null;
		} catch (IOException e) {
        	map.put("errorMsg", "系统异常：" + e.getMessage());
			return "wx/wx-login-exception";
		}
    }
    
    @ResponseBody
    @RequestMapping(value = "/check/{mpId}")
    public R check(@PathVariable("mpId") Integer mpId,
    		HttpServletRequest request, HttpServletResponse response) {
        String code = request.getParameter("code");
        Integer referenceId = null;
        if(request.getParameter("referenceId") != null) {
        	try {
				referenceId = Integer.valueOf(request.getParameter("referenceId"));
			} catch (NumberFormatException e) {
				referenceId = 0;
			}
        }
        
        UserEntity user = null;
        WxMpService weixinService = wxMpConfiguration.getMpService(mpId);
        if (!StringUtils.isNullOrEmpty(code)) {
            try {
				WxMpOAuth2AccessToken accessToken = weixinService.oauth2getAccessToken(code);
			    WxMpUser wxUser = weixinService.oauth2getUserInfo(accessToken, null);
				String ip = RequestUtil.getIpAddrByRequest(request);
				user = userService.loginByWx(wxUser,mpId,ip,referenceId);
			} catch (WxErrorException e) {
				logger.error(e.getMessage(),e);
				return R.error(e.getMessage());
			}
        }else {
			logger.error("code is null");
			return R.error("code is null");
        }
	    Map<String, Object> tokenMap = tokenService.createToken(user.getId());
	    String token = MapUtils.getString("token",tokenMap);
		return R.ok().put("user", user).put("token", token).put("expireTime", tokenMap.get("expireTime"));
    }
    
///////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////	小程序  					///////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////
    @ResponseBody
    @RequestMapping(value = "/wxsilentcheck/{mpId}")
    public R wxSilentCheck(@PathVariable("mpId") Integer mpId,
    		HttpServletRequest request, HttpServletResponse response) {
        String code = request.getParameter("code");
		String ip = RequestUtil.getIpAddrByRequest(request);
        Integer referenceId = null;
        if(request.getParameter("referenceId") != null) {
        	try {
				referenceId = Integer.valueOf(request.getParameter("referenceId"));
			} catch (NumberFormatException e) {
				referenceId = 0;
			}
        }
        UserEntity user = null;
        WxMaService weixinService = wxMaConfiguration.getMaService(mpId);
        try {
            WxMaJscode2SessionResult wxOpenIdUnionId = weixinService.jsCode2SessionInfo(code);
			user = userService.loginByWxXcx(wxOpenIdUnionId,mpId,ip,referenceId);
		} catch (WxErrorException e) {
			logger.error(e.getMessage(),e);
			return R.error(e.getMessage());
		}
				
	    Map<String, Object> tokenMap = tokenService.createToken(user.getId());
	    String token = MapUtils.getString("token",tokenMap);
		return R.ok().put("user", user).put("token", token).put("expireTime", tokenMap.get("expireTime"));
    }
    
    @ResponseBody
    @RequestMapping(value = "/xcxcheck/{mpId}")
    public R xcxCheck(@PathVariable("mpId") Integer mpId,
    		HttpServletRequest request, HttpServletResponse response) {
        String code = request.getParameter("code");
        Integer referenceId = null;
        if(request.getParameter("referenceId") != null) {
        	try {
				referenceId = Integer.valueOf(request.getParameter("referenceId"));
			} catch (NumberFormatException e) {
				referenceId = 0;
			}
        }
        String signature = request.getParameter("signature");
        String rawData = request.getParameter("rawData");
        String encryptedData = request.getParameter("encryptedData");
        String iv = request.getParameter("iv");
		String ip = RequestUtil.getIpAddrByRequest(request);
        UserEntity user = null;
        WxMaService weixinService = wxMaConfiguration.getMaService(mpId);
        try {
			WxMaJscode2SessionResult session = weixinService.getUserService().getSessionInfo(code);
	        String sessionKey = session.getSessionKey();
	        // 用户信息校验
	        if (!weixinService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
	            return R.error("user check failed");
	        }
	        // 解密用户信息
	        WxMaUserInfo wxUser = weixinService.getUserService().getUserInfo(sessionKey, encryptedData, iv);
	        
			user = userService.loginByWxXcx(wxUser,mpId,ip,referenceId);
		} catch (WxErrorException e) {
			logger.error(e.getMessage(),e);
			return R.error(e.getMessage());
		}
				
	    Map<String, Object> tokenMap = tokenService.createToken(user.getId());
	    String token = MapUtils.getString("token",tokenMap);
		return R.ok().put("user", user).put("token", token).put("expireTime", tokenMap.get("expireTime"));
    }
}
